<?php
/**
 * Работа с цветами - класс Open_Color
 * @package OpenStruct
 */

/**
 * Подключаем необходимые файлы
 */
require_once CORE_PATH .'Open/Text'. EXT;

/**
 * Преобразования данных
 */
class Open_Color
{
	/*************
	 * Константы *
	 *************/

	const RGB = 0x01;
	const HSB = 0x02;

	/************
	 * Свойства *
	 ************/

	/**
	 * Цвета X11 в RGB палитре
	 *
	 * @var array
	 */
	static private $webColors = array(
		'aliceblue'			=> 0xF0F8FF,
		'antiquewhite'		=> 0xFAEBD7,
		'aqua'				=> 0x00FFFF,
		'aquamarine'		=> 0x7FFFD4,
		'azure'				=> 0xF0FFFF,
		'beige'				=> 0xF5F5DC,
		'bisque'			=> 0xFFE4C4,
		'black'				=> 0x000000,
		'blanchedalmond'	=> 0xFFEBCD,
		'blue'				=> 0x0000FF,
		'blueviolet'		=> 0x8A2BE2,
		'brown'				=> 0xA52A2A,
		'burlywood'			=> 0xDEB887,
		'cadetblue'			=> 0x5F9EA0,
		'chartreuse'		=> 0x7FFF00,
		'chocolate'			=> 0xD2691E,
		'coral'				=> 0xFF7F50,
		'cornflowerblue'	=> 0x6495ED,
		'cornsilk'			=> 0xFFF8DC,
		'crimson'			=> 0xDC143C,
		'cyan'				=> 0x00FFFF,
		'darkblue'			=> 0x00008B,
		'darkcyan'			=> 0x008B8B,
		'darkgoldenrod'		=> 0xB8860B,
		'darkgray'			=> 0xA9A9A9,
		'darkgreen'			=> 0x006400,
		'darkkhaki'			=> 0xBDB76B,
		'darkmagenta'		=> 0x8B008B,
		'darkolivegreen'	=> 0x556B2F,
		'darkorange'		=> 0xFF8C00,
		'darkorchid'		=> 0x9932CC,
		'darkred'			=> 0x8B0000,
		'darksalmon'		=> 0xE9967A,
		'darkseagreen'		=> 0x8FBC8F,
		'darkslateblue'		=> 0x483D8B,
		'darkslategray'		=> 0x2F4F4F,
		'darkturquoise'		=> 0x00CED1,
		'darkviolet'		=> 0x9400D3,
		'deeppink'			=> 0xFF1493,
		'deepskyblue'		=> 0x00BFFF,
		'dimgray'			=> 0x696969,
		'dodgerblue'		=> 0x1E90FF,
		'firebrick'			=> 0xB22222,
		'floralwhite'		=> 0xFFFAF0,
		'forestgreen'		=> 0x228B22,
		'fuchsia'			=> 0xFF00FF,
		'gainsboro'			=> 0xDCDCDC,
		'ghostwhite'		=> 0xF8F8FF,
		'gold'				=> 0xFFD700,
		'goldenrod'			=> 0xDAA520,
		'gray'				=> 0x808080,
		'green'				=> 0x008000,
		'greenyellow'		=> 0xADFF2F,
		'honeydew'			=> 0xF0FFF0,
		'hotpink'			=> 0xFF69B4,
		'indianred'			=> 0xCD5C5C,
		'indigo'			=> 0x4B0082,
		'ivory'				=> 0xFFFFF0,
		'khaki'				=> 0xF0E68C,
		'lavender'			=> 0xE6E6FA,
		'lavenderblush'		=> 0xFFF0F5,
		'lawngreen'			=> 0x7CFC00,
		'lemonchiffon'		=> 0xFFFACD,
		'lightblue'			=> 0xADD8E6,
		'lightcoral'		=> 0xF08080,
		'lightcyan'			=> 0xE0FFFF,
		'lightgoldenrodyellow'	=> 0xFAFAD2,
		'lightgreen'		=> 0x90EE90,
		'lightgray'			=> 0xD3D3D3,
		'lightpink'			=> 0xFFB6C1,
		'lightsalmon'		=> 0xFFA07A,
		'lightseagreen'		=> 0x20B2AA,
		'lightskyblue'		=> 0x87CEFA,
		'lightslategray'	=> 0x778899,
		'lightsteelblue'	=> 0xB0C4DE,
		'lightyellow'		=> 0xFFFFE0,
		'lime'				=> 0x00FF00,
		'limegreen'			=> 0x32CD32,
		'linen'				=> 0xFAF0E6,
		'magenta'			=> 0xFF00FF,
		'maroon'			=> 0x800000,
		'mediumaquamarine'	=> 0x66CDAA,
		'mediumblue'		=> 0x0000CD,
		'mediumorchid'		=> 0xBA55D3,
		'mediumpurple'		=> 0x9370DB,
		'mediumseagreen'	=> 0x3CB371,
		'mediumslateblue'	=> 0x7B68EE,
		'mediumspringgreen'	=> 0x00FA9A,
		'mediumturquoise'	=> 0x48D1CC,
		'mediumvioletred'	=> 0xC71585,
		'midnightblue'		=> 0x191970,
		'mintcream'			=> 0xF5FFFA,
		'mistyrose'			=> 0xFFE4E1,
		'moccasin'			=> 0xFFE4B5,
		'navajowhite'		=> 0xFFDEAD,
		'navy'				=> 0x000080,
		'oldlace'			=> 0xFDF5E6,
		'olive'				=> 0x808000,
		'olivedrab'			=> 0x6B8E23,
		'orange'			=> 0xFFA500,
		'orangered'			=> 0xFF4500,
		'orchid'			=> 0xDA70D6,
		'palegoldenrod'		=> 0xEEE8AA,
		'palegreen'			=> 0x98FB98,
		'paleturquoise'		=> 0xAFEEEE,
		'palevioletred'		=> 0xDB7093,
		'papayawhip'		=> 0xFFEFD5,
		'peachpuff'			=> 0xFFDAB9,
		'peru'				=> 0xCD853F,
		'pink'				=> 0xFFC0CB,
		'plum'				=> 0xDDA0DD,
		'powderblue'		=> 0xB0E0E6,
		'purple'			=> 0x800080,
		'red'				=> 0xFF0000,
		'rosybrown'			=> 0xBC8F8F,
		'royalblue'			=> 0x4169E1,
		'saddlebrown'		=> 0x8B4513,
		'salmon'			=> 0xFA8072,
		'sandybrown'		=> 0xF4A460,
		'seagreen'			=> 0x2E8B57,
		'seashell'			=> 0xFFF5EE,
		'sienna'			=> 0xA0522D,
		'silver'			=> 0xC0C0C0,
		'skyblue'			=> 0x87CEEB,
		'slateblue'			=> 0x6A5ACD,
		'slategray'			=> 0x708090,
		'snow'				=> 0xFFFAFA,
		'springgreen'		=> 0x00FF7F,
		'steelblue'			=> 0x4682B4,
		'tan'				=> 0xD2B48C,
		'teal'				=> 0x008080,
		'thistle'			=> 0xD8BFD8,
		'tomato'			=> 0xFF6347,
		'turquoise'			=> 0x40E0D0,
		'violet'			=> 0xEE82EE,
		'wheat'				=> 0xF5DEB3,
		'white'				=> 0xFFFFFF,
		'whitesmoke'		=> 0xF5F5F5,
		'yellow'			=> 0xFFFF00,
		'yellowgreen'		=> 0x9ACD32,
	);

	/**
	 * Числовое значение RGB цвета
	 *
	 * @var int
	 */
	private $RGB = FALSE;

	/**********
	 * Методы *
	 **********/

	/**
	 * Конструктор
	 *
	 * @param mixed $value Число (0xFFEEDD), массив (array(0xFF, 0xEE, 0xDD)), либо строка ('#FFEEDD' или название web-цвета)
	 */
	function __construct($value)
	{
		/**
		 * Если число сохраняем
		 */
		if( is_int($value) )
		{
			$this->RGB = $value;
		}
		/**
		 * Если массив преобразуем в число
		 */
		else if( is_array($value) && count($value) == 3 )
		{
			$temp = array_values($value);
			$this->RGB = (($temp[0] & 0xFF) << 16) | (($temp[1] & 0xFF) << 8) | ($temp[2] & 0xFF);
		}
		/**
		 * Если строка пытаемся преобразовать в число или ищем среди web-цветов
		 */
		else if( is_string($value) )
		{
			if( $value{0} == '#' )
			{
				$this->RGB = intval(base_convert(trim($value, '# '), 16, 10)) & 0xFFFFFF;
			}
			else if( isset(self::$webColors[$temp = strtolower($value)]) )
			{
				$this->RGB = self::$webColors[$temp];
			}
		}

		/**
		 * Иначе выдаём ошибку
		 */
		if( $this->RGB === FALSE )
		{
			triggerError(sprintf(Open_Text::getInstance()->dget('errors', 'The value "<b>%s</b>" cannot be converted to color'), $value), E_USER_WARNING);
		}
	}

	/**
	 * Деструктор
	 */
	function __destruct()
	{
	}

	/**
	 * Инвертировать цвет
	 *
	 * @return object $this
	 */
	public function invert()
	{
		$this->RGB = (~$this->RGB & 0xFFFFFF);

		return $this;
	}

	/**
	 * Сделать чёрно-белым
	 *
	 * @return object $this
	 */
	public function grayscale()
	{
		$gray = round(0.3*(($this->RGB >> 16) & 0xFF) + 0.59*(($this->RGB >> 8) & 0xFF) + 0.11*($this->RGB & 0xFF));

		$this->RGB = ($gray << 16 | $gray << 8 | $gray);

		return $this;
	}

	/**
	 * Постеризовать цвет
	 *
	 * @param int $n Количество оттенков от 2 до 255
	 * @return object $this
	 */
	public function posterize($n)
	{
		$n = ($n < 0x02 ? 0x02 : $n);
		$n = ($n > 0xFF ? 0xFF : $n);

		$range = 0xFF/$n;
		$colorSpan = 0xFF/($n-1);

		$R = round( floor((($this->RGB >> 16) & 0xFF)/$range) * $colorSpan );
		$G = round( floor((($this->RGB >> 8) & 0xFF)/$range) * $colorSpan );
		$B = round( floor(($this->RGB & 0xFF)/$range) * $colorSpan );

		$this->RGB = ($R << 16 | $G << 8 | $B);

		return $this;
	}

	/**
	 * Получить цвет в виде числа
	 *
	 * @return int
	 */
	public function toInt()
	{
		return $this->RGB;
	}

	/**
	 * Получить цвет в виде строки
	 *
	 * @return string
	 */
	public function toString()
	{
		return sprintf('#%06X', $this->RGB);
	}

	/**
	 * Перегрузка метода преобразования к строке
	 *
	 * @return string
	 */
	public function __toString()
	{
		return $this->toString();
	}

	/**
	 * Получить цвет в виде массива
	 *
	 * @return string
	 */
	public function toArray()
	{
		return array(($this->RGB >> 16) & 0xFF, ($this->RGB >> 8) & 0xFF, $this->RGB & 0xFF);
	}
}